using System;
using System.Threading;
using System.Windows.Forms;

using Pegasus.Log4Net;

namespace Pegasus.Diagnostics
{

	/// <summary>
	/// This class is used to capture the unhandled exception for a given appliation domain.
	/// </summary>
	/// <example>
	/// ...
	/// 
	/// // Place this code in the application start up section of your program.
	/// UnhandledExceptions unhandledException = new UnhandledExceptions();
	/// unhandledException.OnUnhandledException += new UnhandledExceptionHander( UnhandledExceptions_OnUnhandledException );
	/// 
	/// ...
	/// 
	///	void UnhandledExceptions_OnUnhandledException( Exception e )
	///	{
	///		// Process the unhandled exceptions.
	/// }
	/// </example>
	public class UnhandledExceptions
	{
		// Local Instance Values
		private ILog m_log = LogManager.GetLogger( typeof( UnhandledExceptions ) );

		/// <summary>
		/// Initializes a new instance of the <see cref="UnhandledExceptions"/> class.
		/// </summary>
		public UnhandledExceptions()
		{
			Application.ThreadException += new ThreadExceptionEventHandler( Application_ThreadException );
			AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler( AppDomain_UnhandledException );
			m_log.Debug( "UnhandledExceptions()" );
		}

		/// <summary>
		/// Handles the ThreadException event of the Application control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.Threading.ThreadExceptionEventArgs"/> instance containing the event data.</param>
		private void Application_ThreadException( object sender, ThreadExceptionEventArgs args )
		{
			m_log.DebugFormat( "UnhandledExceptions:Application_ThreadException( sender = {0}, args = {1}", sender, args );
			m_log.Error( "UnhandledExceptions:Application_ThreadException", args.Exception );

			if( OnUnhandledException != null )
			{
				OnUnhandledException( args.Exception );
			}
		}


		/// <summary>
		/// Handles the UnhandledException event of the AppDomain control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.UnhandledExceptionEventArgs"/> instance containing the event data.</param>
		private void AppDomain_UnhandledException( object sender, UnhandledExceptionEventArgs args )
		{
			m_log.DebugFormat( "UnhandledExceptions:AppDomain_UnhandledException( sender = {0}, args = {1}", sender, args );

			Exception e = args.ExceptionObject as Exception;
			if( e != null )
			{
				m_log.Error( "UnhandledExceptions:Application_ThreadException", e );

				if( OnUnhandledException != null )
				{
					OnUnhandledException( e );
				}
			}
			else
			{
				m_log.ErrorFormat( "UnhandledExceptions:Application_ThreadException: Unknown exception type, args.Exception = {0}", args.ExceptionObject );
			}
		}

		/// <summary>
		/// This event is fired when there is an unhandled exception.
		/// </summary>
		public event UnhandledExceptionHander OnUnhandledException;
	}

	/// <summary>
	/// Delegate for the Unhandled Exception event.
	/// </summary>
	/// <param name="e">The exception that was not handled by the application.</param>
	public delegate void UnhandledExceptionHander( Exception e );
}
